import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class MyData{

    volatile int  number=0;

    public void addTo60(){
        this.number=60;
    }

    //此时number前面加了volatile关键字修饰的
    public synchronized void addPlusPlus(){
        number++;
    }

    AtomicInteger atomicInteger=new AtomicInteger();

    public void myatomic(){
        atomicInteger.getAndIncrement();
    }
}

/**
 * 1 验证volatile的可见性
 * 1.1加入int number =0；number变量之前根本没有添加volatile关键字修饰，没有可见性
 * 1.2添加volatitle，可以解决可见性问题
 *
 * 2.验证volatile不保证原子性
 * 2.1 原子性指的是什么意思
 *  不可分割，完整性，也即某个线程正在做某个具体业务时，中间不可以被加塞或则被分割。需要整体完整
 *  要么同时成功，要们同时失败
 * 2.3 volatile不保证原子性案例演示
 */
public class VolatileDemo {
    public static void main(String[] args) {
        //volatileVisibilityDemo();
        MyData myData = new MyData();
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 1; j <= 1000; j++) {
                    myData.addPlusPlus();
                    myData.myatomic();
                }
            },String.valueOf(i)).start();
        }
        //需要等待上面20个线程全部都计算完成后，再用main线程取得最终结果值是多少
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName()+"\t finally number value:"+myData.number);
        System.out.println(Thread.currentThread().getName()+"\t AtomicInteger number value:"+myData.atomicInteger.get());
    }

    ////volatile可以保证可见性，及时通知其它线程主物理内存的值已被修改
    private static void volatileVisibilityDemo() {
        MyData myData = new MyData();  //资源类
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t come in ");
            //暂停一会儿线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.addTo60();
            System.out.println(Thread.currentThread().getName()+"\t update number value: "+myData.number);
        },"A线程").start();

        //第二个线程就是我们的主线程
        while (myData.number==0){
            //main线程就在这里一直等待循环，知道number值不再等于零
        }

        System.out.println(Thread.currentThread().getName()+"\t mission is over main get value:"+myData.number);
    }
}
